package ar.com.coonocer.joy.mdg.util.templating.gsp;

import groovy.lang.Writable;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import ar.com.coonocer.joy.mdg.xmi.core.ModelElement;
import ar.com.coonocer.joy.mdg.xmi.model.Model;

public class GSPNameUtil {

	private static final String SHORT_EXPRESSION_CHARACTER = "##";

	private static Log logger = LogFactory.getLog(GSPNameUtil.class);

	/**
	 * Generates output file name
	 * 
	 * @param templateFile
	 *            por ejemplo:
	 *            D:\proyectos\_Mine\j-oy\trunk\Templates\Xmi2Mvn\Default\BaseUMLType\Stereotype_WAR\dynamic\${umlclass.name}\src\main\webapp\WEB-INF\web.xml.vm
	 * @param templateFolder
	 *            por ejemplo:
	 *            D:\proyectos\_Mine\j-oy\trunk\Templates\Xmi2Mvn\Default
	 * @param destinationFolder
	 *            por ejemplo:
	 *            D:\proyectos\_Mine\j-oy\trunk\Projects\SampleXmi2Mvn\output
	 * @return D:\proyectos\_Mine\j-oy\trunk\Projects\SampleXmi2Mvn\output\
	 *         WAR_XXXX_INET\src\main\webapp\WEB-INF\web.xml
	 */
	public static File getDestinationFile(Model model, ModelElement umlObject, File templateFile, File templateFolder, File destinationFolder) {
		String templateFile2 = templateFile.getAbsolutePath();
		String templateFolder2 = templateFolder.getAbsolutePath();
		//
		String suffix = templateFile2.substring(templateFolder2.length());
		//
		suffix = suffix.replace('\\', '/');
		//
		// quita la barra inicial
		if (suffix.charAt(0) == '/') {
			suffix = suffix.substring(+1);
		}
		//quita el primer nivel de carpetas: UMLModel, UMLPackage, UMLClass, etc.
		suffix = suffix.substring(suffix.indexOf("/") + 1);
		//quita el segundo nivel de carpetas: dynamic
		suffix = suffix.substring(suffix.indexOf("/") + 1);
		//suffix = suffix.substring(suffix.indexOf("/") + 1);
		//
		if (suffix.contains(SHORT_EXPRESSION_CHARACTER)) {
			suffix = resolveShortExpressions(suffix, templateFolder);
		}
		//
		if (suffix.contains("$")) {
			suffix = evaluate(model, umlObject, templateFolder, suffix);
		}
		//
		if (suffix.endsWith(GSPTemplateUtil.TEMPLATE_EXTENSION)) {
			suffix = suffix.substring(0, suffix.lastIndexOf(GSPTemplateUtil.TEMPLATE_EXTENSION));
		}
		//
		return new File(destinationFolder, suffix);
	}

	private static String resolveShortExpressions(String suffix, File templateFolder) {
		//
		logger.debug("Resolving short expressions on " + suffix);
		//
		Properties expressions = new Properties();
		try {
			expressions.load(new FileInputStream(new File(templateFolder, "resources/expressions.properties")));
		} catch (FileNotFoundException e) {
			throw new RuntimeException("Unable to load expressions.properties file required to resolve " + SHORT_EXPRESSION_CHARACTER + " expression", e);
		} catch (IOException e) {
			throw new RuntimeException("Unable to load expressions.properties file required to resolve " + SHORT_EXPRESSION_CHARACTER + " expression", e);
		}
		//
		int ini = 0;
		int pos = suffix.indexOf(SHORT_EXPRESSION_CHARACTER, ini);
		//
		StringBuilder sb = new StringBuilder();
		while (pos != -1) {
			if (pos - ini != 0) {
				sb.append(suffix.substring(ini, pos));
			}
			//
			int ini2 = pos + SHORT_EXPRESSION_CHARACTER.length();
			int pos2 = suffix.indexOf(SHORT_EXPRESSION_CHARACTER, ini2);
			//
			if (pos2 == -1) {
				throw new RuntimeException("Invalid short expression. Escape sequence (" + SHORT_EXPRESSION_CHARACTER + ") must be balanced. Suffix: " + suffix);
			}
			//
			String key = suffix.substring(ini2, pos2);
			String value = expressions.getProperty(key);
			sb.append(value);
			//
			ini = pos2 + SHORT_EXPRESSION_CHARACTER.length();
			pos = suffix.indexOf(SHORT_EXPRESSION_CHARACTER, ini);
		}
		//
		if (ini < suffix.length()) {
			sb.append(suffix.substring(ini));
		}
		//
		return sb.toString();
	}

	private static String evaluate(Model model, ModelElement umlObject, File templateFolder, String expression) {
		//
		logger.debug("Evaluating expression " + expression + " on " + umlObject.getName());
		//
		Writable writable = GSPTemplateUtil.executeGSPTemplate(model, umlObject, templateFolder, null, expression, null);
		//
		String value = writable.toString();
		//
		logger.debug("Result:" + value);
		//
		return value;
	}

}
